#pragma once

#include <cassert>
#include <fstream>
#include <memory>
#include <unistd.h>

#include "util.hpp"

namespace Log
{
    class LogFlushInterface
    {
    public:
        virtual ~LogFlushInterface() = default;
        virtual void Flush(const char *data, size_t len) = 0;
    };


    class StdoutFlushImpl : public LogFlushInterface
    {
    public:
        void Flush(const char *data, size_t len) override
        {
            cout.write(data, len);
        }
    };

    class FileFlush : public LogFlushInterface
    {
    public:
        FileFlush(const std::string &filename) 
            : filename_(filename)
        {
            utils::File::CreateDirectory(utils::File::Path(filename));

            fs_ = fopen(filename.c_str(), "ab");
            if (!fs_)
            {
                std::cout << __FILE__ << __LINE__ << "open log file failed" << std::endl;
                perror(NULL);
            }
        }
        void Flush(const char *data, size_t len) override
        {
            fwrite(data, 1, len, fs_);

            if (ferror(fs_))
            {
                std::cout << __FILE__ << __LINE__ << "write log file failed" << std::endl;
                perror(NULL);
            }

            if(utils::JsonData::GetInstance().flush_log == 1)
            {
                if(fflush(fs_) != EOF)
                    return;
                    
                std::cout << __FILE__ << __LINE__ << "fflush file failed" << std::endl;
                perror(NULL);
            }
            else if(utils::JsonData::GetInstance().flush_log == 2)
            {
                fflush(fs_);
                fsync(fileno(fs_));
            }
        }

    private:
        std::string filename_;
        FILE* fs_ = NULL; 
    };


    class LogFlushFactory
    {
    public:
        template <typename FlushType, typename... Args>
        static std::shared_ptr<LogFlushInterface> CreateLog(Args &&...args)
        {
            return std::make_shared<FlushType>(std::forward<Args>(args)...);
        }
    };
}